// $Id: BlinkToRadioC.nc,v 1.5 2007/09/13 23:10:23 scipio Exp $

/*
 * "Copyright (c) 2000-2006 The Regents of the University  of California.  
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 * 
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */ 

/**
 * Implementation of the BlinkToRadio application.  A counter is
 * incremented and a radio message is sent whenever a timer fires.
 * Whenever a radio message is received, the three least significant
 * bits of the counter in the message payload are displayed on the
 * LEDs.  Program two motes with this application.  As long as they
 * are both within range of each other, the LEDs on both will keep
 * changing.  If the LEDs on one (or both) of the nodes stops changing
 * and hold steady, then that node is no longer receiving any messages
 * from the other node.
 *
 * @author Prabal Dutta
 * @date   Feb 1, 2006
 */
#include <Timer.h>
#include "BlinkToRadio.h"

module BlinkToRadioC {
	uses interface Boot;
	uses interface Leds;
	uses interface Timer<TMilli> as Timer0;
	uses interface Packet;
	uses interface AMPacket;
	uses interface Random;
	uses interface AMSend;
	uses interface Receive;
	uses interface SplitControl as AMControl;
	uses interface FloatConverterIF as fConv;
	uses interface ParameterInit<uint16_t> as Seed;
}
implementation {

	float value;
	float weight;

	message_t pkt;
	bool busy = FALSE;

	void setLeds(uint16_t val) {
		if(val & 0x01) 
			call Leds.led0On();
		else 
			call Leds.led0Off();
		if(val & 0x02) 
			call Leds.led1On();
		else 
			call Leds.led1Off();
		if(val & 0x04) 
			call Leds.led2On();
		else 
			call Leds.led2Off();
	}

	event void Boot.booted() {
		float tmp = 0;
		uint16_t x = call Random.rand16();
		x = (x % NUM_NODES) + 1;
		value = TOS_NODE_ID;
		weight = 1;
		call AMControl.start();
		if( ! busy) {
			BlinkToRadioMsg * btrpkt = (BlinkToRadioMsg * )(call Packet.getPayload(&pkt,
					sizeof(BlinkToRadioMsg)));
			if(btrpkt == NULL) {
				return;
			}
			tmp = value / 2;
			btrpkt->nodeid = TOS_NODE_ID;
			btrpkt->floatnum = call fConv.convFloat_uint32_t(&tmp);
			value = value + tmp;

			tmp = weight / 2;
			btrpkt->floatnum = call fConv.convFloat_uint32_t(&tmp);
			weight = weight + tmp;

			btrpkt->descid = x;
			if(call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(BlinkToRadioMsg)) == SUCCESS) {
				busy = TRUE;
			}
		}
	}

	event void AMControl.startDone(error_t err) {
		if(err == SUCCESS) {
			call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
		}
		else {
			call AMControl.start();
		}
	}

	event void AMControl.stopDone(error_t err) {
	}

	event void Timer0.fired() {
		float tmp = 0;
		uint16_t x = TOS_NODE_ID;
		
		do{
			x = call Random.rand16();
			x = (x % NUM_NODES) + 1;
			}while (x==TOS_NODE_ID);
		
		if( ! busy) {
			BlinkToRadioMsg * btrpkt = (BlinkToRadioMsg * )(call Packet.getPayload(&pkt,
					sizeof(BlinkToRadioMsg)));
			if(btrpkt == NULL) {
				return;
			}
			
			tmp = value/weight;
			btrpkt->est = call fConv.convFloat_uint32_t(&tmp);


			tmp = value / 2;
			btrpkt->nodeid = TOS_NODE_ID;
			btrpkt->floatnum = call fConv.convFloat_uint32_t(&tmp);
			value = tmp;
			
			tmp = weight / 2;
			btrpkt->weight = call fConv.convFloat_uint32_t(&tmp);
			weight = tmp;


			btrpkt->descid = x;
			
			

			if(call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(BlinkToRadioMsg)) == SUCCESS) {
				busy = TRUE;
			}
		}
	}

	event void AMSend.sendDone(message_t * msg, error_t err) {
		if(&pkt == msg) {
			busy = FALSE;
		}
	}

	event message_t * Receive.receive(message_t * msg, void * payload,
			uint8_t len) {
		uint32_t tmp=0;
		float tmp32=0;
		if(len == sizeof(BlinkToRadioMsg)) {
			BlinkToRadioMsg * btrpkt = (BlinkToRadioMsg * ) payload;
			//	setLeds(btrpkt->counter);
			tmp=btrpkt->floatnum;
			tmp32=call fConv.convInt32_tFloat(&tmp);
			if(TOS_NODE_ID == btrpkt->descid) {
				value = value + tmp32;
			}
			tmp=btrpkt->weight;
			tmp32=call fConv.convInt32_tFloat(&tmp);
			if(TOS_NODE_ID == btrpkt->descid) {
				weight = weight + tmp32;
			}
			
		}
		return msg;
	}
}